package com.jingjin.humanityservice.util.ranking;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jingjin.humanityservice.util.ranking.cacheData.CacheDataInRedis;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Component
public class BilibiliRankingHandler {

    private static final HttpClient httpClient = HttpClient.newHttpClient();

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private CacheDataInRedis cacheDataInRedis;

    public Map<String, Object> handleRoute(Map<String, String> queryParams, boolean noCache) throws Exception {
        String type = queryParams.getOrDefault("type", "0");
        Map<String, Object> listResult = getList(type, noCache);


//        listResult = cacheDataInRedis.getCachedData("bilibili:hotSearch"); // 从redis里面拿出缓存数据
//        if (listResult == null) {
//            listResult = getList(type, noCache);
//            cacheDataInRedis.cacheData("bilibili:hotSearch", listResult); // Cache the fresh data
//        }

        Map<String, Object> routeData = new LinkedHashMap<>();
        routeData.put("name", "bilibili");
        routeData.put("favicon", "https://www.bilibili.com/favicon.ico");
        routeData.put("title", "哔哩哔哩");
        Instant nowTime = Instant.now();
        // 将当前时间戳转换为上海时区
        ZonedDateTime Shanghai = nowTime.atZone(ZoneId.of("Asia/Shanghai"));
        routeData.put("nowTime", Shanghai);
        routeData.put("type", "热门榜");
        routeData.put("link", "https://www.bilibili.com/v/popular/rank/all");
        routeData.put("total", ((List<?>) listResult.get("data")).size());

        List<Map<String, Object>> dataList = addIndexToDataList((List<Map<String, Object>>) listResult.get("data"));
        routeData.put("data", dataList);

        // 缓存数据进redis
        cacheDataInRedis.cacheData("bilibili:hotSearch", routeData);

        return routeData;
    }

    private List<Map<String, Object>> addIndexToDataList(List<Map<String, Object>> dataList) {
        return IntStream.range(0, dataList.size())
                .mapToObj(index -> {
                    Map<String, Object> newItem = new LinkedHashMap<>();
                    newItem.put("index", index + 1);
                    newItem.putAll(dataList.get(index));
                    return newItem;
                })
                .collect(Collectors.toList());
    }

    private Map<String, Object> getList(String type, boolean noCache) throws Exception {
        String url = "https://api.bilibili.com/x/web-interface/ranking/v2?tid=" + type + "&type=all&";
        Map<String, Object> result = fetchAndParse(url, noCache);

        if (result != null && result.containsKey("data")) {
            List<Map<String, Object>> list = parseList(result);
            if (list != null && !list.isEmpty()) {
                return createResultMap(list);
            }
        }

        // Fallback to backup API
        url = "https://api.bilibili.com/x/web-interface/ranking?jsonp=jsonp?rid=" + type + "&type=1&callback=__jp0";
        result = fetchAndParse(url, noCache);

        if (result != null && result.containsKey("data")) {
            List<Map<String, Object>> list = parseList(result);
            return createResultMap(list);
        }

        throw new RuntimeException("Failed to retrieve list data from both APIs.");
    }

    private List<Map<String, Object>> parseList(Map<String, Object> result) {
        Map<String, Object> dataMap = (Map<String, Object>) result.get("data");
        return (List<Map<String, Object>>) dataMap.get("list");
    }

    private Map<String, Object> createResultMap(List<Map<String, Object>> list) {
        List<Map<String, Object>> mappedList = list.stream()
                .map(v -> Map.of(
                        "url", v.get("short_link_v2"),
                        "title", v.get("title")
                ))
                .collect(Collectors.toList());

        Map<String, Object> result = new HashMap<>();
        result.put("fromCache", false);
        result.put("updateTime", System.currentTimeMillis());
        result.put("data", mappedList);

        return result;
    }

    private Map<String, Object> fetchAndParse(String url, boolean noCache) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Referer", "https://www.bilibili.com/ranking/all")
                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        JsonNode resultNode = objectMapper.readTree(response.body());
        return objectMapper.convertValue(resultNode, new TypeReference<>() {});
    }

    public Map<String, Object> getRouteAndDataCombined(Map<String, String> queryParams, boolean noCache) throws Exception {
        return handleRoute(queryParams, noCache);
    }

    public Map<String, Object> getBilibiliRanking() throws Exception {
        return getRouteAndDataCombined(Map.of("type", "1"), false);
    }
}
